package com.easy.dn.utils.encryption;


import com.easy.dn.utils.exception.ErrorCode;
import com.easy.dn.utils.exception.ErrorException;

import java.io.UnsupportedEncodingException;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * description AES
 * author zhanqiulin
 * create 2017/8/7
 */
public final class AES {
    /** AES */
    private static final String AES_ALG         = "AES";
    /** AES算法 */
    private static final String AES_CBC_PCK_ALG = "AES/CBC/PKCS5Padding";
    /** 向量 */
    private static final byte[] IV_STRING = initIv();

    private AES() {
    }
    /**
     * 加密
     *
     * @param data 需要加密的内容
     * @param key  加密密码
     * @return
     */
    public static byte[] encrypt(byte[] data, byte[] key) {
        try {
            SecretKeySpec secretKey = new SecretKeySpec(key, AES_ALG);
            IvParameterSpec ivParameterSpec = new IvParameterSpec(IV_STRING);
            Cipher cipher = Cipher.getInstance(AES_CBC_PCK_ALG);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
            byte[] encryptBytes = cipher.doFinal(data);
            return encryptBytes;
        } catch (Exception e) {
            throw new ErrorException(ErrorCode.FAULT, "encrypt fail!");
        }
    }

    /**
     * 解密
     *
     * @param data 待解密内容
     * @param key  解密密钥
     * @return
     */
    public static byte[] decrypt(byte[] data, byte[] key) {
        try {
            SecretKeySpec secretKey = new SecretKeySpec(key, AES_ALG);
            IvParameterSpec ivParameterSpec = new IvParameterSpec(IV_STRING);
            Cipher cipher = Cipher.getInstance(AES_CBC_PCK_ALG);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
            byte[] cleanBytes = cipher.doFinal(data);
            return cleanBytes;
        } catch (Exception e) {
            throw new ErrorException(ErrorCode.FAULT, "decrypt fail!");
        }
    }

    /**
     * description encryptToBase64
     * param 
     * return 
     */
    public static String encrypt(String data, String key) {
        try {
            return Base64.urlEncode2Str(encrypt(data.getBytes(Constants.CHAR_ENCODING), key.getBytes(Constants.CHAR_ENCODING)));
        } catch (Exception e) {
            throw new ErrorException(ErrorCode.FAULT, "encrypt fail!");
        }
    }

    /**
     * description decryptFromBase64
     * param
     * return
     */
    public static String decrypt(String data, String key) {
        try {
            return new String(decrypt(Base64.decodeBase64(data), key.getBytes(Constants.CHAR_ENCODING)), Constants.CHAR_ENCODING);
        } catch (Exception e) {
            throw new ErrorException(ErrorCode.FAULT, "decrypt fail!");
        }
    }

    /**
     * 初始向量的方法, 全部为0. 这里的写法适合于其它算法,针对AES算法的话,IV值一定是128位的(16字节).
     */
    private static byte[] initIv() {
        try {
            return "A-16-Byte-String".getBytes(Constants.CHAR_ENCODING);
        } catch (UnsupportedEncodingException e) {
            throw new ErrorException("生成向量失败");
        }
        
    }

}
